package com.tonggedata.dataapi.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import org.apache.dolphinscheduler.api.utils.PageInfo;

import org.springframework.stereotype.Service;
import cn.hutool.core.bean.BeanUtil;

import com.tonggedata.dataapi.entity.ApiStrategy;
import com.tonggedata.dataapi.service.ApiStrategyService;
import com.tonggedata.dataapi.mapper.ApiStrategyMapper;
import com.tonggedata.dataapi.dto.ApiStrategyDto;
import com.tonggedata.dataapi.dto.ApiStrategyParamDto;
import com.tonggedata.dataapi.util.ApiServiceUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.Constants;
import org.apache.dolphinscheduler.dao.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import cn.hutool.core.util.StrUtil;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Date;

/**
 * ==================================================
 *
 * @author : tonggedata
 * @fileName:
 * @create : 2022-06-19 13:08:47
 * @Description： api策略表, 对应网关各类插件
 * ==================================================
 * @since 1.0.0
 */
@Service
public class ApiStrategyServiceImpl extends ServiceImpl<ApiStrategyMapper, ApiStrategy> implements ApiStrategyService {


    private static final Logger logger = LoggerFactory.getLogger(ApiStrategyServiceImpl.class);

    @Autowired
    private ApiStrategyMapper apiStrategyMapper;

    @Override
    public Map<String, Object> queryApiStrategy(long id) {
        Map<String, Object> result = new HashMap<>();
        ApiStrategy apiStrategy = getById(id);
        if (apiStrategy == null) {
//            putMsg(result, Status.RESOURCE_NOT_EXIST);
            return result;
        }
        // type
        ApiStrategyDto apiStrategyDto = new ApiStrategyDto();
        BeanUtil.copyProperties(apiStrategy, apiStrategyDto);

        result.put(Constants.DATA_LIST, apiStrategyDto);
        ApiServiceUtil.putMsg(result, Status.SUCCESS);
        return result;
    }


    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public Result<Object> delete(User loginUser, long id) {
        Result<Object> result = new Result<>();
        try {
            //query datasource by id
            ApiStrategy apiStrategy = getById(id);
            if (apiStrategy == null) {
                logger.error("resource id {} not exist" , id);
                ApiServiceUtil.putMsg(result, Status.RESOURCE_NOT_EXIST);
                return result;
            }
            if (!ApiServiceUtil.hasPerm(loginUser, apiStrategy.getCreateUser())) {
                ApiServiceUtil.putMsg(result, Status.USER_NO_OPERATION_PERM);
                return result;
            }
            apiStrategyMapper.deleteById(id);
            ApiServiceUtil.putMsg(result, Status.SUCCESS);
        } catch (Exception e) {
            logger.error("delete apiStrategy error" , e);
            throw new RuntimeException("delete apiStrategy error" );
        }
        return result;
    }

    @Override
    public Result queryApiStrategyListPaging(User loginUser, String searchVal, Integer pageNo, Integer pageSize) {
        Result result = new Result();
        Page<ApiStrategy> apiStrategyPage = new Page<>(pageNo, pageSize);
        LambdaQueryWrapper<ApiStrategy> lambdaQuery = new LambdaQueryWrapper<ApiStrategy>();
        if (!ApiServiceUtil.isAdmin(loginUser)) {
            lambdaQuery.eq(ApiStrategy::getCreateUser, loginUser.getUserName());
        }
        if (StrUtil.isNotEmpty(searchVal)) {
            //lambdaQuery.eq(ApiStrategy::getName, searchVal);
        }
        IPage<ApiStrategy> ipage = page(apiStrategyPage, lambdaQuery);
        //转换格式
        PageInfo<ApiStrategy> pageInfo = new PageInfo<>(pageNo, pageSize);
        pageInfo.setTotal((int) ipage.getTotal());
        pageInfo.setTotalList(ipage.getRecords());
        result.setData(pageInfo);
        ApiServiceUtil.putMsg(result, Status.SUCCESS);
        return result;
    }

    @Override
    public Map<String, Object> queryApiStrategyList(User loginUser, String name) {
        Map<String, Object> result = new HashMap<>();

        LambdaQueryWrapper<ApiStrategy> lambdaQuery = new LambdaQueryWrapper<ApiStrategy>();

        if (!ApiServiceUtil.isAdmin(loginUser)) {
            lambdaQuery.eq(ApiStrategy::getCreateUser, loginUser.getUserName());
        }
        if (StrUtil.isNotEmpty(name)) {
            lambdaQuery.like(ApiStrategy::getName, name);
        }
        List<ApiStrategy> apiStrategyList = apiStrategyMapper.selectList(lambdaQuery);

        result.put(Constants.DATA_LIST, apiStrategyList);
        ApiServiceUtil.putMsg(result, Status.SUCCESS);

        return result;
    }


    @Override
    public Result<Object> updateApiStrategy(long id, User loginUser, ApiStrategyParamDto apiStrategyParam) {
        //ApiStrategyUtil.checkApiStrategyParam(apiStrategyParam);
        Result<Object> result = new Result<>();
        ApiStrategy apiStrategy = getById(id);
        if (apiStrategy == null) {
            // putMsg(result, Status.RESOURCE_NOT_EXIST);
            return result;
        }

        if (!ApiServiceUtil.hasPerm(loginUser, apiStrategy.getCreateUser())) {
            ApiServiceUtil.putMsg(result, Status.USER_NO_OPERATION_PERM);
            return result;
        }

        //check name can use or not
        if (!apiStrategy.getName().trim().equals(apiStrategy.getName()) && checkName(apiStrategy.getName())) {
            //putMsg(result, Status.DATASOURCE_EXIST);
            return result;
        }

        BeanUtil.copyProperties(apiStrategyParam, apiStrategy, CopyOptions.create().setIgnoreNullValue(true));
        try {
            apiStrategy.setUpdateTime(new Date());
            apiStrategy.setUpdateUser(loginUser.getUserName());
            apiStrategyMapper.updateById(apiStrategy);
            ApiServiceUtil.putMsg(result, Status.SUCCESS);
        } catch (DuplicateKeyException ex) {
            logger.error("Update apiStrategy error." , ex);
            ApiServiceUtil.putMsg(result, Status.DATASOURCE_EXIST);
        }
        return result;
    }

    private boolean checkName(String name) {
        LambdaQueryWrapper<ApiStrategy> lambdaQuery = new LambdaQueryWrapper<ApiStrategy>();
        lambdaQuery.eq(ApiStrategy::getName, name);
        List<ApiStrategy> apiStrategyList = apiStrategyMapper.selectList(lambdaQuery);
        return apiStrategyList != null && !apiStrategyList.isEmpty();
    }

    @Override
    public Result<Object> createApiStrategy(User loginUser, ApiStrategyParamDto apiStrategyParam) {
        //DatasourceUtil.checkApiStrategyParam(apiStrategyParam);
        Result<Object> result = new Result<>();
        // check name can use or not
      /* if (checkName(apiStrategyParam.getName())) {
            putMsg(result, Status.DATA_API_GROUP_ERROR);
            return result;
        }*/

        // build apiStrategy
        ApiStrategy apiStrategy = new ApiStrategy();
        Date now = new Date();


        //apiStrategy.setCreateUser(loginUser.getUserName());
        BeanUtil.copyProperties(apiStrategyParam, apiStrategy, CopyOptions.create().setIgnoreNullValue(true));

        //apiStrategy.setCreateTime(now);
        apiStrategy.setUpdateTime(now);
        try {
            apiStrategyMapper.insert(apiStrategy);
            ApiServiceUtil.putMsg(result, Status.SUCCESS);
        } catch (DuplicateKeyException ex) {
            logger.error("Create apiStrategy error." , ex);
            ApiServiceUtil.putMsg(result, Status.DATA_API_GROUP_ERROR);
        }

        return result;
    }

}
